﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using NHibernate;
using NHibernate.Cfg;
using NHibernate.Criterion;
using eBookDomain;

namespace eBookDataAccess
{
  public class NHibernateSessionManager
  {
    private ISessionFactory _sessionFactory;

    public NHibernateSessionManager()
    {
      _sessionFactory = GetSessionFactory();
    }
    
    private ISessionFactory GetSessionFactory()
    {
      return (new Configuration()).Configure().BuildSessionFactory();
    }     
  
    public ISession GetSession()
    {      
      return _sessionFactory.OpenSession();
    }    
    
  }
  
  public class NHibernateDataProvider   
  {  
  
    private ISession _session;      
    public ISession Session
    {
      set {_session = value;}
    }
    
    public NHibernateDataProvider(ISession session)
    {
      _session = session;      
    }      
  
    public T GetById<T>(int id)
    {     
      return _session.Get<T>(id);
    }
    
    public Book GetBookByISBN(string isbn)
    {
      return _session.CreateQuery( "select from Book b where b.ISBN10 = :isbn or b.ISBN13 = :isbn" )
                .SetString( "isbn", isbn )
                .UniqueResult<Book>();    
    }
    
    public IList<Book> GetBookByTitle(string title)
    {
        return _session.CreateCriteria( typeof( Book ) )
                  .Add( new NHibernate.Criterion.LikeExpression("Title", title, MatchMode.Anywhere ))
                  .List<Book>(); 

    }


    public IList<Book> GetBookByAuthor(int authorId)
    {
      return _session.CreateCriteria(typeof(Book))
                     .CreateCriteria("Authors")
                     .Add(Expression.Eq("AuthorID", authorId))
                     .List<Book>();
    }
    
    public IList<Book> GetBookByPublisher(int publisherId)
    {
      return _session.CreateCriteria(typeof(Book))
                     .Add(Expression.Eq("PublisherID", publisherId))
                     .List<Book>();
    }
    
    public Publisher GetPublisherByName(string publisherName)
    {
      return _session.CreateCriteria(typeof(Publisher))
                     .Add(Expression.Eq("Name", publisherName))
                     .UniqueResult<Publisher>();        
    }

    public Author GetAuthorByName(string authorName)
    {
      return _session.CreateCriteria(typeof(Author))
                     .Add(Expression.Eq("Name", authorName))
                     .UniqueResult<Author>();        
    }

    public Link GetLinkByPath(string path)
    {
      return _session.CreateCriteria(typeof(Link))
                     .Add(Expression.Eq("Path", path))
                     .UniqueResult<Link>();        
    }

            
    #region CRUD 
    
    public IList<Book> GetBookByExample( Book bookSample )
    {
      return _session.CreateCriteria( typeof( Book ) )
                     .Add( Example.Create( bookSample ) )
                     .List<Book>();
    }

    public int AddBook( Book book )
    {
      using ( ITransaction tx = _session.BeginTransaction() )
      {
        try
        {
          // save method returns the identity of the saved object
          int newId = ( int ) _session.Save( book );
          _session.Flush();
          tx.Commit();
          return newId;
        }
        catch ( NHibernate.HibernateException )
        {
          tx.Rollback();
          throw;
        }
      }
    }

    public void DeleteBook( Book book )
    {
      using ( ITransaction tx = _session.BeginTransaction() )
      {
        try
        {
          _session.Delete( book );
          _session.Flush();
          tx.Commit();
        }
        catch ( NHibernate.HibernateException )
        {
          tx.Rollback();
          throw;
        }
      }
    }

    public void UpdateBook( Book book )
    {
      using ( ITransaction tx = _session.BeginTransaction() )
      {
        try
        {
          _session.Update( book );
          _session.Flush();
          tx.Commit();
        }
        catch ( NHibernate.HibernateException )
        {
          tx.Rollback();
          throw;
        }
      }
    }

    public void SaveOrUpdate( IList<Book> books )
    {
      using ( ITransaction tx = _session.BeginTransaction() )
      {
        try
        {
          foreach ( Book b in books )
            _session.SaveOrUpdate( b );

          _session.Flush();
          tx.Commit();
        }
        catch ( NHibernate.HibernateException )
        {
          tx.Rollback();
          throw;
        }
      }
    }

    public void SaveOrUpdate(object entity)
    {
      using ( ITransaction tx = _session.BeginTransaction() )
      {
        try
        {
          _session.SaveOrUpdate( entity );
          _session.Flush();
          tx.Commit();
        }
        catch ( NHibernate.HibernateException )
        {
          tx.Rollback();
          throw;
        }
      }
    }
        
    #endregion
    
  }
}
